import http from '@ohos.net.http';
import util from '@ohos.util';
import { robotState, runState as runStateEnum } from './enum';
import socket from '@ohos.net.socket';
import wifiManager from '@ohos.wifiManager';
import display from '@ohos.display';
import deviceInfo from '@ohos.deviceInfo';
import connection from '@ohos.net.connection'
// import app from '@ohos.application.appManager';
// import window from '@ohos.window';
// import wifi from '@ohos.wifi';
// import account_distributedAccount from '@ohos.account.distributedAccount';
import runningLock from '@ohos.runningLock';
import promptAction from '@ohos.promptAction';
import { robotIds } from './robotCommon';
// import bluetoothManager from '@ohos.bluetoothManager';
export let testPad_fakeMap = false;

const testPad_toastString = 'testPad_toast';

export const {MIN_SAFE_INTEGER} = Number;

export const {request,destroy} = http.createHttp();

export const {isSafeInteger,MAX_SAFE_INTEGER} = Number;

export const {round,min,max,log2,log10,ceil,atan2,PI,floor} = Math;

export const { log, error, info } = console;

export const httpPort = 8000;

export const space = 5;

export const stringify = (e: unknown) => {
  try {
    return JSON.stringify(e);
  } catch (e) {
    error(stringify(e));
    return '';
  }
};

// info('hjx1',stringify(deviceInfo))
// info('hjx2', stringify(display.getDefaultDisplaySync()))
// display.getAllDisplays().then(e => {
//   info('hjx3', stringify(e));
// })
// info('hjx4',stringify(connection.getDefaultNetSync().netId))
// connection.getDefaultNet().then(e => {
//   info('hjx5', stringify(e.netId));
// })
// connection.getAllNets().then(e => {
//   info('hjx6', stringify(e));
// })
// connection.getAppNet().then(e => {
//   info('hjx7', stringify(e));
// })
// account_distributedAccount.getDistributedAccountAbility().getOsAccountDistributedInfo().then((data) => {
//   console.log('hjx8' + stringify(data));
// });
//GET_LOCAL_ACCOUNTS
// info('hjx9', runningLock.isSupported(runningLock.RunningLockType.BACKGROUND))
// info('hjx10', runningLock.isSupported(runningLock.RunningLockType.PROXIMITY_SCREEN_CONTROL))
//TODO
// info('hjx11',bluetoothManager.getLocalName())
// info('hjx12',stringify(bluetoothManager.getState()))
// info('hjx13',stringify(bluetoothManager.getBtConnectionState()))
// info('hjx14',stringify(bluetoothManager.getPairedDevices()))
// info('hjx15',stringify(bluetoothManager.getBluetoothScanMode()))
//@ohos.batteryInfo
//@ohos.power
//@ohos.thermal
//@ohos.usbManager

//tcp解码，ArrayBuffer变成string
// export const textDecoder = util.TextDecoder.create("utf-8");

export let judgmentPreview = (() => {
  try {
    if (stringify(deviceInfo) !== '{"deviceType":"","manufacture":"","brand":"","marketName":"","productSeries":"","productModel":"","softwareModel":"","hardwareModel":"","hardwareProfile":"","serial":"","bootloaderVersion":"","abiList":"","securityPatchTag":"","displayVersion":"","incrementalVersion":"","osReleaseType":"","osFullName":"","majorVersion":0,"seniorVersion":0,"featureVersion":0,"buildVersion":0,"sdkApiVersion":0,"firstApiVersion":0,"versionId":"","buildType":"","buildUser":"","buildHost":"","buildTime":"","buildRootHash":"","udid":""}') {
      return false;
    }
    if (stringify(display.getDefaultDisplaySync()) !== '{"id":0,"name":"[PC Preview] unkonwn name","alive":true,"refreshRate":0,"rotation":0,"width":0,"height":0,"densityDPI":0,"densityPixels":0,"scaledDensity":0,"xDPI":0,"yDPI":0}') {
      return false;
    }
    if (connection.getDefaultNetSync().netId !== 0) {
      return false;
    }
    if (stringify(wifiManager.isWifiActive()) !== '"[PC Preview] unkonwn type"') {
      return false;
    }
    if (stringify(wifiManager.getCandidateConfigs()) !== '[]') {
      return false;
    }
    if (stringify(wifiManager.getCountryCode()) !== '"[PC Preview] unkonwn type"') {
      return false;
    }
    if (stringify(wifiManager.getIpInfo()) !== '{"ipAddress":0,"gateway":0,"netmask":0,"primaryDns":0,"secondDns":0,"serverIp":0,"leaseDuration":0}') {
      return false;
    }
    if (stringify(runningLock.isSupported(runningLock.RunningLockType.BACKGROUND)) !== '"[PC Preview] unkonwn type"') {
      return false;
    }
    if (stringify(runningLock.isSupported(runningLock.RunningLockType.PROXIMITY_SCREEN_CONTROL)) !== '"[PC Preview] unkonwn type"') {
      return false;
    }
    return true;
  }
  catch (e) {
    error(e);
    return false;
  }
})() || testPad_fakeMap;

export const changeTestPad = () => {
  judgmentPreview = !judgmentPreview;
  testPad_fakeMap = !testPad_fakeMap;
}

// const buf2String = (buf: ArrayBuffer) => textDecoder.decodeWithStream(new Uint8Array(buf));

export const isNumber = (n: number | undefined) => typeof (n) === 'number' && isSafeInteger(n);

export const {screen_width,screen_height} = (() => {
  const initialWidth = 2200;
  const initialHeight = 1440;
  try {
    const {width=initialWidth,height=initialHeight} = display?.getDefaultDisplaySync();
    return { screen_width: width || initialWidth, screen_height: height || initialHeight };
  } catch (e) {
    return { screen_width: initialWidth, screen_height: initialHeight };
  }
})();

export const minScale = ~~(screen_height / screen_width * 10) / 10;

export const screenWidth9 = (screen_width) * .9 / 3;

export const screenWidth3 = screenWidth9 * .3;

export const screenWidth1 = ~~(screenWidth3 / 2);

export const screenWidth3To1 = screenWidth3 - screenWidth1;

export const heightMinusScreenWidth1 = ~~((screen_height - screenWidth3) / 2);

export const screenWidthDiv10 = ~~(screen_width / 40);

export const fingerCount = 1;

const byteLength = 9

export const makeSendData = ({state=0, runState=0,speed=0,endX=0,endY=0 }: {
  // readonly robotId?: number;
  readonly state: robotState;
  readonly runState?: runStateEnum;
  readonly speed?: number;
  readonly endX?: number;
  readonly endY?: number;
}) => {
  const buffer = new ArrayBuffer(byteLength);
  const uint8Array = new Uint8Array(buffer);
  uint8Array[0] = state;
  uint8Array[1] = runState;
  uint8Array[2] = speed;
  const d = new DataView(buffer, 3);
  d.setInt16(0, endX, false);
  d.setInt16(2, endY, false);
  return buffer;
};

export const parseReceiveData = (a: ArrayBuffer): {
  // readonly robotId?: number;
  readonly state: robotState;
  readonly x?: number;
  readonly y?: number;
  readonly r?: number;
} => {
  const u = new Uint8Array(a);
  const state = u[0];
  const d = new DataView(a, 3);
  const x = d.getInt16(0, false);
  const y = d.getInt16(2, false);
  const r = d.getInt16(4, false);
  return { state, x, y, r };
};

export const ipString = 'ip';

export const initIpEnd = 99;

export const ipStart = '172.168.11.';

const initialIp = `${ipStart}${initIpEnd}`;
const { Has, SetAndProp, Prop, Get, SetAndLink, Link, Size, Set, SetOrCreate } = AppStorage;
const { GetShared } = LocalStorage;
const { PersistProp,
// PersistProps,
  Keys } = PersistentStorage;

export const storage: LocalStorage = GetShared()?? new LocalStorage();
//?? new LocalStorage({ [ipString]: initialIp })
// const { set, has, get, setOrCreate, setAndLink, setAndProp, link, prop, size } = storage;
export const getIp = (ipStr = ipString): string => {
  const appGetIp = Get<string>(ipStr) || Prop(ipStr) || Link(ipStr) || initialIp;
  try {
    return storage.get<string>(ipStr) || storage.prop<string>(ipStr).get() || storage.setAndProp(ipStr, initialIp).get() || storage.setAndLink(ipStr, initialIp).get() || storage.link<string>(ipStr).get() || appGetIp;
  } catch (e) {
    error(e);
    return appGetIp;
  }
};
//,ipString?:string
export const AppSetIp = (ip: string = getIp(), ipStr: string = ipString) => {
  if (ipStr !== ipString)
    PersistProp(ipStr, ip);
  Set(ipStr, ip);
  SetOrCreate(ipStr, ip);
  SetAndLink(ipStr, ip).set(ip);
  SetAndProp(ipStr, ip).set(ip);
};

export const setIpLocalStorage = (ip = getIp(), ipStr: string = ipString) => {
  // try {
  new LocalStorage({ [ipStr]: ip });
  storage.setOrCreate(ipStr, ip);
  storage.set(ipStr, ip);
  storage.setAndProp(ipStr, ip).set(ip);
  storage.setAndLink(ipStr, ip).set(ip);
  // } catch (e) {
  //   error(e);
  // }
};

export const ip = (() => {
  PersistProp(ipString, initialIp);
  const getTheIp = getIp();
  // try {
  if (!storage.has(ipString) || !storage.get<string>(ipString) || !storage.prop<string>(ipString).get() || !storage.link<string>(ipString).get() || !storage.size() || !storage.setAndProp(ipString, getTheIp).get() || !storage.setAndLink(ipString, getTheIp).get()) {
    setIpLocalStorage(getTheIp);
  }
  // } catch (e) {
  //   error(e);
  // }
  // if (!Keys().length) {
  // PersistProps([{ key: ipString, defaultValue: getTheIp }]);
  // }
  if (!Has(ipString) || !SetAndProp<string>(ipString, getTheIp).get() || !Prop(ipString) || !Get<string>(ipString) || !SetAndLink(ipString, getTheIp).get() || !Link(ipString) || !Size()) {
    AppSetIp(getTheIp);
  }
  return getTheIp;
});

export let testPad_toast = (() => {
  PersistentStorage.PersistProp(testPad_toastString, false);
  const t = AppStorage.Get<string | boolean>(testPad_toastString);
  if (typeof (t) === 'string') {
    return t === 'true';
  }
  return t;
})();

export const changeTestPad_toast = () => {
  testPad_toast = !testPad_toast;
  AppStorage.SetOrCreate(testPad_toastString, testPad_toast);
};

export const ipsString = 'ips';

export type ipsType = {
  name: string;
  ip: string;
  online?: boolean;
}

export type ipsTypeArr = ipsType[];

const initIps: ipsTypeArr = robotIds.map((i, index) => ({ ip: `172.168.11.${initIpEnd + index}`, name: `机器人${index + 1}` }));

export const ips: ipsTypeArr = (() => {
  PersistentStorage.PersistProp(ipsString, stringify(initIps));
  const t = AppStorage.Get<string | ipsTypeArr>(ipsString);
  if (typeof (t) === 'string') {
    try {
      return JSON.parse(t) || initIps;
    } catch (e) {
      error(e);
      return initialIp;
    }
  }
  return t;
})();

export const sendPort = 5001;

export const receivePort = 5001;

export const udp = socket.constructUDPSocketInstance();

// const ipNum = (() => {
//   try {
//     return wifiManager.getIpInfo().ipAddress;
//   } catch (e) {
//     error(e);
//     return 0;
//   }
// })();
const {showToast} = promptAction;

export const arrBuff2String = (message: ArrayBuffer) => {
  const m2s: string[] = [];
  const u = new Uint8Array(message);
  for (let i = 0;i < message.byteLength; i++) {
    m2s.push(u[i].toString())
  }
  return m2s.join(' ');
}

export const udpSend = async (ip: string, SendData: Parameters<typeof makeSendData>[0]) => {
  const data = makeSendData(SendData);
  if (!data) {
    error('send fail, err: data is empty');
    return;
  }
  if (judgmentPreview) {
    info('WantSend', ip, arrBuff2String(data))
    const p = parseReceiveData(data);
    return p;
  }
  return await udp.send({
    data, address: {
      address: ip,
      port: sendPort
    }
  }).then(() => {
    info('send success');
    if (testPad_toast)
      showToast({ message: '发送成功\n' + stringify(SendData) });
  }).catch(async err => {
    error('send fail', stringify(err));
    showToast({ message: '发送失败' + (testPad_toast ? ('\n' + stringify(SendData)) : '') });
    throw new Error(err)
    // await tcp.close();
    // setTimeout(bind, 5e3);
  });
};

//本地IP的字符串形式
// export const localIp = (ipNum >>> 24) + '.' + (ipNum >> 16 & 0xFF) + '.' + (ipNum >> 8 & 0xFF) + '.' + (ipNum & 0xFF);
